%define SYS_READ 0
%define SYS_WRITE 1
%define SYS_EXIT 60
%define STDOUT 1
%define STDIN 0
%define NEW_LINE `\n`
%define NUMBER_BASE 10
%define ASCII_ZERO '0'
%define ASCII_MINUS '-'
%define ASCII_PLUS '+'
%define ASCII_SPACE ' '
%define ASCII_TAB `\t`

section .text

 
; Принимает код возврата и завершает текущий процесс
exit:
    mov rax, SYS_EXIT
    syscall

; Принимает указатель на нуль-терминированную строку, возвращает её длину
;указатель в rdi
string_length:
    xor rax,rax
    .loop:
        mov sil, byte [rdi]
        test sil,sil
        jz .out
        inc rax
        inc rdi
        jmp .loop
    .out:
        ret

; Принимает указатель на нуль-терминированную строку, выводит её в stdout
; указатель в rdi
print_string:
    push    rdi
    call    string_length
    pop     rsi              
    mov     rdx, rax          
    mov     rax, SYS_WRITE
    mov     rdi, STDOUT
    syscall
    ret

; Переводит строку (выводит символ с кодом 0xA)
; не юзаем call-ret
print_newline:
    mov rdi, NEW_LINE

; Принимает код символа и выводит его в stdout
; код символа в rdi
print_char:
    push rdi
    mov rsi, rsp
    mov rax, SYS_WRITE
    mov rdi, STDOUT
    mov rdx, 1
    syscall
    pop rdi
    ret

; Выводит знаковое 8-байтовое число в десятичном формате 
; число в rdi
; не юзаем call-ret
print_int:
    test rdi, rdi
    jnl print_uint
    push rdi
    mov rdi, ASCII_MINUS
    call print_char
    pop rdi
    neg rdi

; Выводит беззнаковое 8-байтовое число в десятичном формате 
; число в rdi
print_uint:
    mov rax, rdi
    mov rsi, NUMBER_BASE
    dec rsp
    mov byte[rsp], 0
    mov r9, 1
    .loop:
        xor rdx, rdx
        div rsi
        add rdx, ASCII_ZERO
        dec rsp
        inc r9
        mov byte[rsp],dl
        test rax, rax
        jz .printing
        jmp .loop
    .printing:
        mov rdi, rsp
        push r9
        call print_string
        pop r9
        add rsp, r9
        ret

; Принимает два указателя на нуль-терминированные строки, возвращает 1 если они равны, 0 иначе
; указатели в rdi и rsi
string_equals:
    .loop:
        mov cl, byte[rdi]
        mov dl, byte[rsi]
        cmp cl,dl
        jne .return_f
        test cl,cl
        jz .return_s
        inc rdi
        inc rsi
        jmp .loop
    .return_s:
        xor rax, rax
        mov rax,1
        ret
    .return_f:
        xor rax,rax
        ret
        

; Читает один символ из stdin и возвращает его. Возвращает 0 если достигнут конец потока
read_char:
    dec       rsp
    mov       rsi, rsp
    mov       rax, SYS_READ
    xor       rdi, rdi
    mov       rdx, 1
    syscall
    test      rax, rax
    jz        .end
    xor       rax, rax
    mov al,   [rsp]
    .end:
        inc rsp
        ret



; Принимает: адрес начала буфера, размер буфера
; Читает в буфер слово из stdin, пропуская пробельные символы в начале, .
; Пробельные символы это пробел 0x20, табуляция 0x9 и перевод строки 0xA.
; Останавливается и возвращает 0 если слово слишком большое для буфера
; При успехе возвращает адрес буфера в rax, длину слова в rdx.
; При неудаче возвращает 0 в rax
; Эта функция должна дописывать к слову нуль-терминатор
;rdi - buf ->r12, rsi - size ->r13
read_word:
    push r12
    push r13
    push r14
    test rsi,rsi
    jz .bad_end
    mov r12, rdi
    mov r13, rsi
    xor r14, r14
    .skip:
        call read_char
        cmp al,ASCII_SPACE
        jz .skip
        cmp al,ASCII_TAB
        jz .skip
        cmp al,NEW_LINE
        jz .skip
    .read:
        test al, al
        jz .end
        cmp r13, r14
        je .bad_end
        cmp al,ASCII_SPACE
        jz .end
        cmp al,ASCII_TAB
        jz .end
        cmp al,NEW_LINE
        jz .end
        mov [r12+r14], al
        inc r14
        call read_char
        jmp .read
    .bad_end:
        xor rdx,rdx
        xor rax,rax
        jmp .ret
    .end:
        cmp r13, r14
        je .bad_end
        mov byte [r12+r14], 0
        mov rdx, r14
        mov rax,r12
    .ret:
        pop r14
        pop r13
        pop r12
        ret

 
    
; Принимает указатель на строку, указатель на буфер и длину буфера
; Копирует строку в буфер
; Возвращает длину строки если она умещается в буфер, иначе 0
;rdi,rsi -str, buf, rdx - len(buf)
string_copy:
    push rdx
    xor rcx, rcx
    .loop:
        test rdx, rdx
        jz .end_buf
        mov cl, byte [rdi]
        mov [rsi],cl
        inc rdi
        inc rsi
        dec rdx
        test cl,cl
        jz .end_line
        jmp .loop
    .end_line:
        pop rax
        sub rax, rdx
        push rax
        jmp .ok
    .end_buf:
        mov cl,byte [rdi]
        test cl,cl
        jz .ok
    .f:
        pop rdx
        xor rax, rax
        jmp .ret
    .ok:
        pop rax
    .ret:
        ret
; Принимает указатель на строку, пытается
; прочитать из её начала беззнаковое число.
; Возвращает в rax: число, rdx : его длину в символах
; rdx = 0 если число прочитать не удалось
parse_uint:
    xor rax, rax
    xor r9, r9
    mov rsi, NUMBER_BASE
    .loop:
        mov cl, byte [rdi+r9]
        test cl,cl
        jz .ret
        cmp cl, ASCII_ZERO
        jl .ret
        cmp cl, ASCII_ZERO+9
        jg .ret
        sub cl, ASCII_ZERO
        inc r9
        mul rsi
        add rax, rcx
        jmp .loop
    .ret:
        mov rdx, r9
        ret




; Принимает указатель на строку, пытается
; прочитать из её начала знаковое число.
; Если есть знак, пробелы между ним и числом не разрешены.
; Возвращает в rax: число, rdx : его длину в символах (включая знак, если он был) 
; rdx = 0 если число прочитать не удалось
parse_int:
    xor rax, rax
    xor rdx,rdx
    mov r8, 0
    mov r9, 0
    mov cl, byte[rdi]
    cmp cl, ASCII_MINUS
    je .minus
    cmp cl, ASCII_PLUS
    je .plus
    .read:
        push r9
        push r8
        call parse_uint
        pop r8
        pop r9
        test rdx,rdx
        jz .ret
        test r8,r8
        jz .end
        neg rax
        jmp  .end
    .minus:
        inc r8 ;if minus
    .plus:
        inc r9 ; for right length in rdx
        inc rdi 
        jmp .read
    .end:
        add rdx, r9 ;adding sing if it was
    .ret:
        ret